﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.Collections;

namespace EasyMvvm
{
    public sealed class MappingEntry : DependencyObject
    {

        public Type ViewType
        {
            get { return (Type)GetValue(ViewTypeProperty); }
            set { SetValue(ViewTypeProperty, value); }
        }

        public Type ViewModelType
        {
            get { return (Type)GetValue(ViewModelTypeProperty); }
            set { SetValue(ViewModelTypeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ViewType.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ViewTypeProperty =
            DependencyProperty.Register("ViewType", typeof(Type), typeof(MappingEntry), new PropertyMetadata(null));

        // Using a DependencyProperty as the backing store for ViewType.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ViewModelTypeProperty =
            DependencyProperty.Register("ViewModelType", typeof(Type), typeof(MappingEntry), new PropertyMetadata(null));

        public MappingEntry()
        { }

        public MappingEntry(Type viewType, Type viewModelType)
        {
            this.ViewType = viewType;
            this.ViewModelType = viewModelType;
        }
    }

    public sealed class ViewModelMapping : ICollection<MappingEntry>, IList<MappingEntry>, IList, ICollection, IEnumerable
    {
        object locker = new object();

        List<MappingEntry> internalList = new List<MappingEntry>();

        #region ICollection<MappingEntry> Members

        bool ICollection<MappingEntry>.Contains(MappingEntry item)
        {
            lock (locker)
                return internalList.Contains(item);
        }

        void ICollection<MappingEntry>.CopyTo(MappingEntry[] array, int arrayIndex)
        {
            lock (locker)
                internalList.CopyTo(array, arrayIndex);
        }

        void ICollection<MappingEntry>.Clear()
        {
            lock (locker)
                internalList.Clear();
        }


        void ICollection<MappingEntry>.Add(MappingEntry item)
        {
            Add(item);
        }

        int ICollection<MappingEntry>.Count
        {
            get
            {
                lock (locker)
                    return internalList.Count;
            }
        }

        bool ICollection<MappingEntry>.IsReadOnly
        {
            get { return false; }
        }

        bool ICollection<MappingEntry>.Remove(MappingEntry item)
        {
            return Remove(item);
        }

        #endregion

        #region IEnumerable<MappingEntry> Members

        IEnumerator<MappingEntry> IEnumerable<MappingEntry>.GetEnumerator()
        {
            lock (locker)
            {
                List<MappingEntry> tempList = new List<MappingEntry>(internalList.ToArray());
                return tempList.GetEnumerator();
            }
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            lock (locker)
                return internalList.ToArray().GetEnumerator();
        }

        #endregion
        
        private static void VerifyType(object value)
        {
            if (value == null)
                throw new ArgumentNullException("value");
            if (value.GetType() != typeof(MappingEntry))
                throw new ArgumentException("Must be of type MappingEntry");
        }

        #region IList<MappingEntry> Members

        int IList<MappingEntry>.IndexOf(MappingEntry item)
        {
            lock (locker)
                return internalList.IndexOf(item);
        }

        void IList<MappingEntry>.Insert(int index, MappingEntry item)
        {
            lock (locker)
                internalList.Insert(index, item);
        }

        void IList<MappingEntry>.RemoveAt(int index)
        {
            lock (locker)
                internalList.RemoveAt(index);
        }
        
        public void Add(MappingEntry item)
        {
            lock (locker)
                internalList.Add(item);
        }

        public bool Remove(MappingEntry item)
        {
            lock (locker)
                return internalList.Remove(item);
        }

        MappingEntry IList<MappingEntry>.this[int index]
        {
            get
            {
                lock (locker)
                    return internalList[index];
            }
            set
            {
                lock (locker)
                    internalList[index] = value;
            }
        }

        #endregion

        #region ICollection Members

        int ICollection.Count
        {
            get
            {
                lock (locker)
                    return internalList.Count;
            }
        }


        void ICollection.CopyTo(Array array, int index)
        {
            if (array == null)
                throw new ArgumentNullException("array");
            if (array.GetType() != typeof(MappingEntry[]))
                throw new ArgumentException("Must be of type MappingEntry[]", "array");
            lock (locker)
                internalList.CopyTo((MappingEntry[])array, index);
        }

        bool ICollection.IsSynchronized
        {
            get { return true; }
        }

        object ICollection.SyncRoot
        {
            get { return locker; }
        }

        #endregion


        #region IList Members

        void IList.Clear()
        {
            lock (locker)
                internalList.Clear();
        }

        bool IList.IsReadOnly
        {
            get { return false; }
        }

        int IList.Add(object value)
        {
            VerifyType(value);
            lock (locker)
            {
                MappingEntry entry = (MappingEntry)value;
                internalList.Add(entry);
                return internalList.IndexOf(entry);
            }

        }

        bool IList.Contains(object value)
        {
            VerifyType(value);
            lock (locker)
            {
                return internalList.Contains((MappingEntry)value);
            }
        }

        int IList.IndexOf(object value)
        {
            VerifyType(value);
            lock (locker)
            {
                return internalList.IndexOf((MappingEntry)value);
            }
        }

        void IList.Insert(int index, object value)
        {
            VerifyType(value);
            lock (locker)
            {
                internalList.Insert(index, (MappingEntry)value);
            }
        }

        bool IList.IsFixedSize
        {
            get { return false; }
        }

        void IList.Remove(object value)
        {
            VerifyType(value);
            lock (locker)
            {
                internalList.Remove((MappingEntry)value);
            }
        }


        void IList.RemoveAt(int index)
        {
            lock (locker)
                internalList.RemoveAt(index);
        }

        object IList.this[int index]
        {
            get
            {
                lock (locker)
                {
                    return internalList[index];
                }
            }
            set
            {
                VerifyType(value);
                lock (locker)
                {
                    internalList[index] = (MappingEntry)value;
                }
            }
        }

        #endregion


    }
}
